// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: implementation of CImplActionDestroy.
//   $Id$


#include "stdafx.h"
#include "implactiondestroy.h"
#include "xformsElementDestroy.h"

#include "implBind.h"
#include "model.h"
#include "singlenodebindingondemand.h"
#include "GetEnclosingBindingOf.h"
#include "implInstance.h"
CImplActionDestroy::CImplActionDestroy(CXFormsElementDestroy * pXFormsElement)
:m_pBind(0)
,m_pRefEvaluator(0)
{
}

CImplActionDestroy::~CImplActionDestroy(void)
{
	delete m_pRefEvaluator;
	m_pRefEvaluator = 0;
}


void CImplActionDestroy::ResolveBindings() 
{
	ResolveEvaluationContext();	
	//bind takes precedence
	if(m_sBind)
	{	
		if(m_pXForms)
			m_pXForms->getBind(m_sBind,m_pBind);
	}
	else if(m_sRef)
	{
		if(m_pModel && !m_pRefEvaluator)
			m_pRefEvaluator = new CSingleNodeBindingOnDemand(m_pModel,m_sRef);
	}
}

HRESULT CImplActionDestroy::GetNodeToDestroy(IXMLDOMNode ** ppNodeToDestroy)
{
	HRESULT hr;
	// Bug 787 - If the xf:destroy is a decsendant of xf:model it is possible that the 
	// binding has not been successful due to the xf:destory been processed before the xf:model.
	// In which case so of these will be null.
	if(!(m_pBind || m_pRefEvaluator) || !m_pModel || !m_pContextParent)
		ResolveBindings();

	if(m_pBind)
	{
		hr = m_pBind->GetNodeAt(0,ppNodeToDestroy);
	}
	else if(m_pRefEvaluator)
	{
		CComPtr<IXMLDOMNode> pContext;		
		GetXPathContext(&pContext);
		hr = m_pRefEvaluator->GetNode(pContext,ppNodeToDestroy);
	}
	else
	{
		hr = E_FAIL;
	}
	return hr;
}

HRESULT CImplActionDestroy::PerformAction()
{
	HRESULT hr = hr = S_FALSE;
	//The node to delete is selected from the Single Node Binding attributes.
	CComPtr<IXMLDOMNode> pNodeToDestroy;
	GetNodeToDestroy(&pNodeToDestroy);
	if(pNodeToDestroy)
	{
		// We need to determine which xf:model and xf:instance from which the 
		// node is to be deleted from before we delete it.
		CImplModel * pModel		= NULL;
		CImplInstance * pInst	= NULL;
		// Find the xf:model which contains the xf:instance that the node to be
		// deleted is stored.
		if(m_pXForms)
			m_pXForms->findModel(pNodeToDestroy, &pModel);
		// Once we've got the xf:instance we can now locate the particular xf:instance.
		if(pModel)
			pModel->findInstance(pNodeToDestroy, &pInst);

		hr = DestroyNodeIfAppropriate(pNodeToDestroy);
		if(S_OK == hr && m_pModel)
		{
			// If we've located the xf:instance we need to dispatch the xforms-destroy
			// event as we've successfully deleted the node.
			if(pInst)
				pInst->FireEvent(EVENT_DESTROY);
			// We also need to rebuild the xf:model in which the xf:instance is stored.
			if(pModel)
				pModel->rebuild(m_pXForms->IsInDeferredUpdate());
		}
	}
	return hr;
}

HRESULT CImplActionDestroy::DestroyNodeIfAppropriate(IXMLDOMNode * pNodeToDestroy) const
{
	HRESULT hr = E_INVALIDARG;
	//TODO: check for readonly?  What about descendents?  Could be a big job!
	if(pNodeToDestroy)
	{
		//If the node is a root node or a namespace node then the action has no effect 
		DOMNodeType type;
		pNodeToDestroy->get_nodeType(&type);
		//There is nodeType that corresponds to namespace,
		//Test comes later.
		if(NODE_DOCUMENT == type)
		{
			hr = S_FALSE;
		}
		//otherwise the node is removed from the instance.
		else
		{
			CComPtr<IXMLDOMNode> pParent;
			pNodeToDestroy->get_parentNode(&pParent);
			if(pParent)
			{
				hr = pParent->removeChild(pNodeToDestroy,0);
				//TODO: If a node was successfully removed from the instance an xforms-destroy event is dispatched.
			}
			else
			{
				//It may be an attribute!
				
				CComQIPtr<IXMLDOMAttribute> pAttr(pNodeToDestroy);
				if(pAttr)
				{
					//Test that it is not a namespace
					CComBSTR sPrefix;
					pAttr->get_prefix(&sPrefix);
					if(sPrefix == L"xmlns")
					{
						hr = S_FALSE;
					}
					else
					{
						CComBSTR sParentPath(L"..");
						pAttr->selectSingleNode(sParentPath,&pParent);
						CComQIPtr<IXMLDOMElement> pEl(pParent);
						if(pEl)
						{
							CComBSTR bsName;
							hr = pEl->removeAttributeNode(pAttr,0);
						}
					}
				}
			}
		}
	
	}
	return hr;
}

